﻿using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Xceed.Document.NET;
using Xceed.Words.NET;

namespace BatchReplaceWordExcelText
{
    public partial class FrmMain : Form
    {
        private delegate void ShowMessageBoxDelegate(string message, string title, MessageBoxIcon icon);
        private void DoWorkInAnotherThread(object messageObj, object titleObj, object icon)
        {
            string message = (string)messageObj;

            // 检查是否需要跨线程调用  
            if (this.InvokeRequired)
            {
                ShowMessageBoxDelegate del = new ShowMessageBoxDelegate(ShowMessageBoxWithParams);
                this.Invoke(del, new object[] { message, titleObj, icon });
            }
            else
            {
                ShowMessageBoxWithParams(message, (string)titleObj, (MessageBoxIcon)icon);
            }
        }

        private void ShowMessageBoxWithParams(string message, string title, MessageBoxIcon icon)
        {
            MessageBox.Show(this, message, title, MessageBoxButtons.OK, icon);
        }

        private Thread _thread;
        public FrmMain()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
            this.FormClosing += (ss, ee) =>
            {
                if (_thread != null && _thread.IsAlive) _thread.Abort();
            };
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            new TextBoxDragDrop(txtDefaultPath);
            ConfigInfo config = ConfigMgr.Get();
            txtDefaultPath.Text = config.DefaultPath;
            txtFindText.Text = config.FindText;
            txtReplaceText.Text = config.ReplaceText;
        }

        private void wordTextReplace(string fn, string searchValue, string newValue)
        {
            using (DocX document = DocX.Load(fn))
            {
                foreach (Paragraph paragraph in document.Paragraphs)
                {
                    StringReplaceTextOptions textOptions = new StringReplaceTextOptions();
                    textOptions.SearchValue = searchValue;
                    textOptions.NewValue = newValue;
                    paragraph.ReplaceText(textOptions);
                }
                document.Save();
            }
        }
        private void excelTextReplace(string fn, string searchValue, string newValue)
        {
            IWorkbook workbook;
            using (FileStream file = new FileStream(fn, FileMode.Open, FileAccess.Read))
            {
                string extension = Path.GetExtension(fn).ToLower().Trim();
                if (extension == ".xls")
                    workbook = new HSSFWorkbook(file); // 对于.xlsx文件  
                else
                    workbook = new XSSFWorkbook(file); // 对于.xlsx文件  
                                                       // 如果是.xls文件，则使用 new HSSFWorkbook(file);  
            }
            int sheetCount = workbook.NumberOfSheets;
            for (int index = 0; index < sheetCount; index++)
            {
                ISheet sheet = workbook.GetSheetAt(index); // 假设你只想操作第一个工作表  
                for (int row = 0; row <= sheet.LastRowNum; row++)
                {
                    if (sheet.GetRow(row) != null)
                    {
                        for (int col = 0; col < sheet.GetRow(row).LastCellNum; col++)
                        {
                            ICell cell = sheet.GetRow(row).GetCell(col);
                            if (cell != null && cell.ToString().Contains(searchValue))
                            {
                                cell.SetCellValue(cell.ToString().Replace(searchValue, newValue));
                            }
                        }
                    }
                }
            }
            using (FileStream file = new FileStream(fn, FileMode.Create, FileAccess.Write))
            {
                workbook.Write(file);
            }
        }

        private void btnReplace_Click(object sender, EventArgs e)
        {
            string defaultPath = txtDefaultPath.Text.Trim();
            if (!Directory.Exists(defaultPath))
            {
                MessageBox.Show("默认位置不存在", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            string findText = txtFindText.Text;
            if (findText == "")
            {
                MessageBox.Show("查找字符不能为空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            ConfigInfo config = new ConfigInfo();
            config.DefaultPath = txtDefaultPath.Text.Trim();
            config.FindText = findText;
            config.ReplaceText = txtReplaceText.Text.Trim();
            ConfigMgr.Save(config);
            _thread = new Thread(new ThreadStart(workService));
            _thread.Start();
        }

        private string filterFile(string fn)
        {
            HashSet<string> extensions = new HashSet<string>();
            extensions.Add(".xls");
            extensions.Add(".xlsx");
            extensions.Add(".doc");
            extensions.Add(".docx");

            string extenion = Path.GetExtension(fn).ToLower().Trim();
            if (!extensions.Contains(extenion)) return string.Empty;
            FileInfo fileInfo = new FileInfo(fn);
            if ((fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
            {
                return string.Empty;
            }
            // 检查文件是否为只读  
            if ((fileInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
            {
                // 取消只读属性  
                fileInfo.Attributes = fileInfo.Attributes & ~FileAttributes.ReadOnly;
                // 验证更改是否生效  
                if ((fileInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                {
                    throw new Exception($"文件是只读的，无法修改:{fn}");
                }
            }
            return fn;
        }
        private void workService()
        {
            try
            {
                foreach (Control control in this.Controls) control.Enabled = false;
                progressBar.Enabled = true;
                this.Cursor = Cursors.WaitCursor;

                string defaultPath = txtDefaultPath.Text.Trim();
                string findText = txtFindText.Text;
                string replaceText = txtReplaceText.Text;

                string[] files = Directory.GetFiles(defaultPath, "*.*", SearchOption.AllDirectories);
                progressBar.Value = 0;
                progressBar.Minimum = 0;
                progressBar.Maximum = files.Length;
                foreach (string file in files)
                {
                    progressBar.Value += 1;
                    if (filterFile(file) == string.Empty) continue;

                    string extenion = Path.GetExtension(file).ToLower().Trim();
                    if (extenion == ".doc" || extenion == ".docx")
                        wordTextReplace(file, findText, replaceText);
                    else if (extenion == ".xls" || extenion == ".xlsx")
                        excelTextReplace(file, findText, replaceText);
                }
                DoWorkInAnotherThread("执行完成", "提示", MessageBoxIcon.Information);
            }
            catch (ThreadAbortException) { }
            catch (Exception ex)
            {
                DoWorkInAnotherThread(ex.Message, "提示", MessageBoxIcon.Warning);
            }
            finally
            {
                foreach (Control control in this.Controls) control.Enabled = true;
                this.Cursor = Cursors.Default;
            }
        }
        private void btnDefaultPath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            string oldPath = txtDefaultPath.Text.Trim();
            if (Directory.Exists(oldPath))
                dlg.SelectedPath = oldPath;
            if (dlg.ShowDialog() != DialogResult.OK) return;
            txtDefaultPath.Text = dlg.SelectedPath;
        }
    }
}
